﻿using FaissOperation.FaissIndex.Native;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Navigation;

namespace FaissOperation.FaissIndex.Index
{
    public sealed class FlatIndex : IFaissIndex
    {
        private IntPtr indexPtr = IntPtr.Zero;
        private bool disposed = false;

        public int Dimension { get; private set; }

        public bool IsTrained => true;

        public FlatIndex(int dimension, FaissMetricType metricType)
        {
            if (dimension <= 0)
                throw new ArgumentException("Dimension must be positive", nameof(dimension));

            Dimension = dimension;

            var err = FaissNative.faiss_IndexFlat_new(out indexPtr, dimension, metricType);
            if (err != 0)
                throw new Exception($"创建 FlatIndex 失败, 错误码={err}");

            if (indexPtr == IntPtr.Zero)
                throw new Exception("创建 FlatIndex 失败: 返回了空指针");
        }

        public IntPtr GetNativePtr()
        {
            ThrowIfDisposed();
            return indexPtr;
        }

        public void Add(float[] vector)
        {
            ThrowIfDisposed();
            FaissUtils.SafeAdd(indexPtr, vector, Dimension);
        }

        public void BatchAdd(float[][] vectors)
        {
            ThrowIfDisposed();
            FaissUtils.SafeBatchAdd(indexPtr, vectors, Dimension);
        }

        public (long[] ids, float[] distances) Search(float[] query, int topK)
        {
            ThrowIfDisposed();
            return FaissUtils.SafeSearch(indexPtr, query, topK, Dimension);
        }

        /// <summary>
        /// 重建索引 - 清空所有数据但保持索引结构
        /// </summary>
        public void Rebuild()
        {
            ThrowIfDisposed();
            FaissUtils.SafeRebuild(indexPtr);
        }

        private void ThrowIfDisposed()
        {
            if (disposed) throw new ObjectDisposedException(nameof(FlatIndex));
        }

        public void Dispose()
        {
            if (!disposed && indexPtr != IntPtr.Zero)
            {
                FaissNative.faiss_Index_free(indexPtr);
                indexPtr = IntPtr.Zero;
                disposed = true;
            }
            GC.SuppressFinalize(this);
        }

        public void Train(float[][] vectors)
        {
            //无需训练
        }

        ~FlatIndex() => Dispose();
    }

}
